package g.beny.framework.web;

import g.beny.framework.constant.Constant;

import java.math.BigDecimal;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.nutz.dao.Cnd;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
/**
 * Cnd
 * 
 * @author GodSon(wmails@126.com)
 */
public class CndInjector {
	private static final Log log = Logs.getLog(CndInjector.class);

	private static final String LT = "LT";// <条件查询
	private static final String GT = "GT";// >条件查询
	private static final String EQ = "EQ";// =条件查询
	private static final String NE = "NE";// !=条件查询
	private static final String LE = "LE";// <=条件查询
	private static final String GE = "GE";// >=条件查询
	private static final String LK = "LK";// like条件查询
	private static final String LKL = "%LK";// like左匹配条件查询
	private static final String RKL = "LK%";// like右匹配条件查询

	private static final String AND = "AND";// AND查询
	private static final String OR = "OR";// OR或者
	private static final String ANDN = "ANDN";// AND NOT
	private static final String ORN = "ORN";// OR NOT

	private static final String BD = "BD";// BigDecimal
	private static final String BL = "BL";// 布尔类型
	private static final String D = "D";// 日期
	private static final String DG = "DG";// 日期类型，并且把其时分秒设置为最大，即为23:59:59
	private static final String DL = "DL";// 日期类型，并且把其时分秒设置为0
	private static final String FT = "FT";// float
	private static final String L = "L";// Long
	private static final String N = "N";// Integer
	private static final String S = "S";// 字符串
	private static final String SN = "SN";// Short

	
	@SuppressWarnings("unchecked")
	public static Cnd get(HttpServletRequest req) {
		Map<String, String> pMap = new HashMap<String, String>();
		Enumeration<String> paramEnu = req.getParameterNames();
		while (paramEnu.hasMoreElements()) {
			String paramName = paramEnu.nextElement();
			if (paramName.startsWith("Q_")) {
				String paramValue = (String) req.getParameter(paramName);
				if (Strings.isEmpty(paramValue))
					continue;
				pMap.put(paramName, paramValue);
			}
		}

		Cnd cnd = buildParams(pMap);

		String sort = req.getParameter(Constant.Page.SORT);
		String order = req.getParameter(Constant.Page.ORDER);
		String rows = req.getParameter(Constant.Page.ROWS);
		String page = req.getParameter(Constant.Page.PAGE);

		if (!Strings.isEmpty(order) && !Strings.isEmpty(sort)) {
			if (order.equalsIgnoreCase("desc"))
				cnd.desc(sort);
			else
				cnd.asc(sort);
		} else if (!Strings.isEmpty(sort)) {
			cnd.asc(sort);
		}
		
		if(!Strings.isEmpty(page) && !Strings.isEmpty(rows)){
			cnd.limit(Integer.parseInt(page), Integer.parseInt(rows));
		}
		return cnd;
	}

	/**
	 * 添加过滤的查询条件
	 * 
	 * @param pMap
	 *            过滤的查询参数名称
	 *            <p>
	 *            过滤的查询参数名称格式必须为: Q_paramName_S 或者 Q_paramName_S_EQ 或者  Q_paramName_S_EQ_AND<br/>
	 *            其中<b>Q_</b>表示该参数为查询的参数<br/>
	 *            <b>paramName</b>查询的字段名称<br/>
	 *            <b>S</b>代表该参数的类型为字符串类型,该位置的其他值有：<br/>
	 *            D=日期，BD=BigDecimal，FT=float,N=Integer,SN=Short,L=Long,
	 *            S=字符串,BL=布尔类型 DL=日期类型，并且把其时分秒设置为0
	 *            DG=日期类型，并且把其时分秒设置为最大，即为23:59:59。<br/>
	 * 			  <b>EQ</b>代表是条件类型，该位置的其他值有：<br/>
	 *            LT，GT，EQ，NE，LE，GE,LK，<br/>
	 *            分别代表<,>,=,!=,<=,>=,like的条件查询<br/>
	 *            <b>AND</b>代表是条件连接方式，该位置的其他值有：<br/>
	 *            AND，OR，ANDN，ORN
	 */
	private static Cnd buildParams(Map<String, String> pMap) {
		Cnd cnd = Cnd.limit();
		if (pMap != null) {
			Iterator<String> it = pMap.keySet().iterator();
			while (it.hasNext()) {
				String qKey = it.next();
				String qValue = pMap.get(qKey);

				String[] fieldInfo = qKey.split("[_]");
				if (fieldInfo.length == 3) {
					Object hValue = convertObject(fieldInfo[2], qValue, LK);
					cnd.and(fieldInfo[1], "like", hValue);
				} else if (fieldInfo.length == 4) {
					Object hValue = convertObject(fieldInfo[2], qValue,
							fieldInfo[3]);
					cnd.and(fieldInfo[1], condition(fieldInfo[3]), hValue);
				} else if (fieldInfo.length == 5) {
					Object hValue = convertObject(fieldInfo[2], qValue,fieldInfo[3]);
					if (AND.equals(fieldInfo[4])) {
						cnd.and(fieldInfo[1], condition(fieldInfo[3]),hValue);
					}else if (ANDN.equals(fieldInfo[4])) {
						cnd.andNot(fieldInfo[1], condition(fieldInfo[3]),hValue);
					} else if (OR.equals(fieldInfo[4])) {
						cnd.or(fieldInfo[1], condition(fieldInfo[3]), hValue);
					} else if (ORN.equals(fieldInfo[4])) {
						cnd.orNot(fieldInfo[1], condition(fieldInfo[3]), hValue);
					} else {
						cnd.and(fieldInfo[1], condition(fieldInfo[3]), hValue);
					}
				} else {
					if (log.isWarnEnabled())
						log.warnf("错误的查询表达式"
								+ qKey
								+ "。请检查格式，例：(Q_paramName_S 或者 Q_paramName_S_EQ 或者  Q_paramName_S_EQ_AND)");
				}
			}
		}
		return cnd;
	}

	/**
	 * 判断条件类型
	 * @param cd
	 * 			条件标识
	 * @return
	 */
	private static String condition(String cd) {
		if (LT.equals(cd)) {
			return "<";
		} else if (GT.equals(cd)) {
			return ">";
		} else if (EQ.equals(cd)) {
			return "=";
		} else if (NE.equals(cd)) {
			return "!=";
		} else if (LE.equals(cd)) {
			return "<=";
		} else if (GE.equals(cd)) {
			return ">=";
		} else {
			return "like";
		}
	}

	/**
	 * 字段类型转换
	 * 
	 * @param type 
	 * 			值类型标识
	 * @param paramValue
	 * 			值
	 * @param op
	 * 			条件
	 * @return
	 */
	private static Object convertObject(String type, String paramValue, String op) {
		Object value = null;
		try {
			if (S.equals(type)) {// 大部的查询都是该类型，所以放至在头部
				if (LK.equals(op)) {
					value = "%" + paramValue + "%";
				} else if (LKL.equals(op)) {
					value = "%" + paramValue;
				} else if (RKL.equals(op)) {
					value = paramValue + "%";
				} else {
					value = paramValue;
				}
			} else if (L.equals(type)) {
				value = new Long(paramValue);
			} else if (N.equals(type)) {
				value = new Integer(paramValue);
			} else if (BD.equals(type)) {
				value = new BigDecimal(paramValue);
			} else if (BL.equals(type)) {
				value = new Boolean(paramValue);
			} else if (FT.equals(type)) {
				value = new Float(paramValue);
			} else if (SN.equals(type)) {
				value = new Short(paramValue);
			} else if (D.equals(type)) {
				value = parseDate(paramValue, new String[] { "yyyy-MM-dd",
				"yyyy-MM-dd HH:mm:ss" });
			} else if (DL.equals(type)) {
				Calendar cal = Calendar.getInstance();
				cal.setTime(parseDate(paramValue, new String[] { "yyyy-MM-dd" }));
				value = setStartDay(cal).getTime();
			} else if (DG.equals(type)) {
				Calendar cal = Calendar.getInstance();
				cal.setTime(parseDate(paramValue, new String[] { "yyyy-MM-dd" }));
				value = setEndDay(cal).getTime();
			} else {
				value = paramValue;
			}
		} catch (Exception ex) {
			if (log.isWarnEnabled())
				log.warnf("类型转换错误！" + ex.getMessage());
		}
		return value;
	}

	/**
	 * 格式化时间
	 * 
	 * @param str
	 * 			时间字符串
	 * @param parsePatterns
	 * 			格式化条件
	 * @return
	 */
	private static Date parseDate(String str, String[] parsePatterns) {
		if ((str == null) || (parsePatterns == null)) {
			if (log.isWarnEnabled())
				log.warnf("日期和模式不能为空！");
			return null;
		}

		SimpleDateFormat parser = null;
		ParsePosition pos = new ParsePosition(0);
		for (int i = 0; i < parsePatterns.length; ++i) {
			if (i == 0)
				parser = new SimpleDateFormat(parsePatterns[0]);
			else {
				parser.applyPattern(parsePatterns[i]);
			}
			pos.setIndex(0);
			Date date = parser.parse(str, pos);
			if ((date != null) && (pos.getIndex() == str.length())) {
				return date;
			}
		}

		if (log.isWarnEnabled())
			log.warnf("无法解析的日期: " + str, -1);

		return null;
	}

	/**
	 * 设置当前时间为当天的最初时间（即00时00分00秒）
	 * 
	 * @param cal
	 * 			Calendar
	 * @return
	 */
	private static Calendar setStartDay(Calendar cal) {
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		return cal;
	}

	/**
	 * 设置当前时间为当天的结束时间（即23时59分59秒）
	 * 
	 * @param cal
	 * 			Calendar
	 * @return
	 */
	private static Calendar setEndDay(Calendar cal) {
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		return cal;
	}
}
